#include "util.h"
#include <execinfo.h>
#include <sys/time.h>
#include <dirent.h>
#include <string.h>

#include "log.h"
#include "fiber.h"

namespace sylar {

Logger::ptr g_logger = SYLAR_LOG_NAME("system");

pid_t GetThreadId() {
	return syscall(SYS_gettid);
}

uint64_t GetFiberId() {
	return Fiber::GetFiberId();
}

void Backtrace(std::vector<std::string>& bt, int size, int skip) {
    void** array = (void**)malloc((sizeof(void*) * size));
    size_t s = ::backtrace(array, size);

    char** strings = backtrace_symbols(array, s);
    if (strings == NULL) {
        SYLAR_LOG_ERROR(g_logger) << "backtrace_symbols error";  
        return;
    }

    for (size_t i = skip; i < s; ++i) {
        bt.push_back(strings[i]);
    }

    free(strings);
    free(array);
}

std::string BacktraceToString(int size, int skip, const std::string& prefix) {
    std::vector<std::string> bt;
    Backtrace(bt, size, skip);

    std::stringstream ss;
    for (size_t i = 0; i < bt.size(); ++i) {
        ss << prefix << bt[i] << std::endl;
    }

    return ss.str();
}

uint64_t GetCurrentMS() {
    struct timeval tv;
    gettimeofday(&tv, NULL);

    return tv.tv_sec * 1000ul + tv.tv_usec / 1000;
}

uint64_t GetCurrentUS() {
    struct timeval tv;
    gettimeofday(&tv, NULL);

    return tv.tv_sec * 1000 * 1000ul + tv.tv_usec;
}

std::string Time2Str(time_t ts, const std::string& format) {
	struct tm tm;
	localtime_r(&ts, &tm);
	char buf[64] = {0};
	strftime(buf, sizeof(buf), format.c_str(), &tm);
	return buf;
}

void FSUtil::ListAllFile(std::vector<std::string>& files, 
                            const std::string& path,
                            const std::string& subfix) {
    if (access(path.c_str(), 0) != 0) {
        return;
    }

    DIR *dir = opendir(path.c_str());
    if (dir == nullptr) {
        return;
    }

    struct dirent *dp = nullptr;
    while ((dp = readdir(dir)) != nullptr) {
        if (dp->d_type == DT_DIR) {
            if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
                continue;
            }

            ListAllFile(files, path + "/" + dp->d_name, subfix);
        } else if (dp->d_type == DT_REG) {
            std::string filename(dp->d_name);
            
            if (subfix.empty()) {
                files.push_back(path + "/" + filename);
            } else {
                if (filename.size() < subfix.size()) {
                    continue;
                }

                if (filename.substr(filename.length() - subfix.size()) == subfix) {
                    files.push_back(path + "/" + filename); 
                }
            }
        }
    }

    closedir(dir);
}

}

